/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sheep.model.graph;

import edu.uci.ics.jung.exceptions.ConstraintViolationException;
import edu.uci.ics.jung.graph.Edge;
import edu.uci.ics.jung.graph.Vertex;
import edu.uci.ics.jung.graph.decorators.EdgeShape;
import java.util.logging.Level;
import java.util.logging.Logger;
import sheep.model.*;
import org.apache.commons.collections.bidimap.DualHashBidiMap;

import edu.uci.ics.jung.graph.impl.DirectedSparseEdge;
import edu.uci.ics.jung.graph.impl.DirectedSparseGraph;
import edu.uci.ics.jung.graph.impl.DirectedSparseVertex;
import edu.uci.ics.jung.utils.UserData;
import edu.uci.ics.jung.visualization.AbstractLayout;
import edu.uci.ics.jung.visualization.DefaultSettableVertexLocationFunction;
import edu.uci.ics.jung.visualization.Layout;
import edu.uci.ics.jung.visualization.ShapePickSupport;
import edu.uci.ics.jung.visualization.StaticLayout;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.util.Iterator;
import java.util.LinkedList;
import sheep.JUNG.utils.OurModalGraphMouse;
import sheep.JUNG.utils.OurPluggableRenderer;
import sheep.JUNG.utils.OurVertexShape;
import sheep.controller.Workspace;
import sheep.view.jung.utils.HitTips;
import sheep.view.jung.utils.VertexLabel;
//import sheep.view.jung.utils.VertexShape;
import java.util.Calendar;
import java.util.Set;
import java.awt.Graphics2D;
import java.io.IOException;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

/**
 *
 * @author geek
 */
public class Graph extends DirectedSparseGraph {



  public static enum Direction{
    BOTH,
    FORWARD,
    BACKWARD
  }
  
  //////////////////////////////////////////////////////////////////////////////

  protected  DualHashBidiMap mapNomVertex = new DualHashBidiMap();
  
  private LinkedList<Task> sortedTasks = new LinkedList<Task>();
  
  private Task startTask;
  private Task endTask;
  
  private String name;
  private DefaultSettableVertexLocationFunction vertexLocations = new DefaultSettableVertexLocationFunction();
   	
  private VisualizationViewer vv;
  private AbstractLayout layout;
   
  
  private DefaultSettableVertexLocationFunction autoVertexLocations = new DefaultSettableVertexLocationFunction();
   	
  private VisualizationViewer autoVv;
  private AbstractLayout autoLayout;  
  
  
  
  
  
  
  
// Gestionnaire d'affichages, formes, couleurs,...
protected OurPluggableRenderer pr; 
	
        Workspace workSpace;
  //////////////////////////////////////////////////////////////////////////////


         
  /**
  * Constructeur
  */
  public Graph(Workspace workSpace){
    this();
    this.workSpace = workSpace;
    
    pr.setVertexShapeFunction(new OurVertexShape(layout, workSpace));
    pr.setVertexPaintFunction(new OurVertexShape(layout,workSpace));
    pr.setVertexStringer(new VertexLabel());
    pr.setEdgeShapeFunction(new EdgeShape.Line()); 
    pr.setEdgePaintFunction(new OurVertexShape(layout,workSpace));
	         

  }
  
  public Graph(){
    super();
    // Gestionnaire de position des vecteurs
    vertexLocations = new DefaultSettableVertexLocationFunction();
    //definitions du layout 
    layout = new StaticLayout(this);
    layout.initialize(new Dimension(800,600), vertexLocations);
      
    // Rendu des elements de graph
    pr = new OurPluggableRenderer();  

    // Gestionnaire de vue
    vv = new VisualizationViewer(layout,pr); 
    vv.setPickSupport(new ShapePickSupport());      
    vv.setFocusable(true);
    vv.setBackground(Color.WHITE); 
    vv.setForeground(Color.darkGray); 
    vv.setToolTipFunction(new HitTips());
    //vv.setToolTipText("Projet : projet1");    
    	    	    
    // Gestionnaire de position des vecteurs
    autoVertexLocations = new DefaultSettableVertexLocationFunction();
    //definitions du layout 
    autoLayout = new StaticLayout(this);
    autoLayout.initialize(new Dimension(800,600), autoVertexLocations);
      
    // Gestionnaire de vue
    autoVv = new VisualizationViewer(autoLayout,pr); 
    autoVv.setPickSupport(new ShapePickSupport());      
    autoVv.setFocusable(true);
    autoVv.setBackground(Color.WHITE); 
    autoVv.setForeground(Color.darkGray); 
    autoVv.setToolTipFunction(new HitTips());
    //autoVv.setToolTipText("Projet : projet1");  
    
    
    
    startTask = new Task("start", 0, workSpace);
    endTask = new Task("end", 0, workSpace);
    this.addVertex(startTask);
    this.addVertex(endTask);
    
    this.addUserDatum("Key", mapNomVertex, UserData.SHARED);
  }	


  //////////////////////////////////////////////////////////////////////////////

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
  
  
  
  /**
  * Gets the vertex associated to a task 
  *
  * @param task the task from which the vertex is to be retrieved
  * @return the vertex associated to the argument
  */
  public OurVertex getVertex(Task task){
    OurVertex vertex = (OurVertex)(mapNomVertex.get(task));
    return vertex;
  }
  
  
  public OurVertex getVertex(int id){
    for(Object v : this.getVertices()){
      if(((OurVertex)v).getTask().getID() == id)
        return (OurVertex)v;
    }
    return null;
  }

  //////////////////////////////////////////////////////////////////////////////

  /**
  * Creates a vertex from a task and adds it to the graph
  *
  * @param task the task from which the vertex is to be created
  * @return the vertex added to the graph
  */

  public void addVertex (Task task){
    /* Creation of Vertex*/ 
    Vertex vertex = new OurVertex();
    vertex.addUserDatum("Key",task,UserData.REMOVE);
    mapNomVertex.put(task,vertex);
    
    if(task.getName().equals("start")){
      task.setLocation(new Point (50,220));
      task.setAutoLocation(new Point (50,220));
    }else if (task.getName().equals("end")){
      task.setLocation(new Point ( 900, 220));
      task.setAutoLocation(new Point ( 900, 220));
    }else{
      task.setLocation(new Point ( 500,220));
      task.setAutoLocation(new Point ( 900, 220));
   
    }
    vertexLocations.setLocation(vertex, vv.inverseTransform(task.getLocation()));
    autoVertexLocations.setLocation(vertex, vv.inverseTransform(task.getAutoLocation()));
    
    
    for(Iterator<?> iterator=this.getVertices().iterator(); iterator.hasNext(); ) {
	Vertex v= (Vertex)iterator.next();layout.lockVertex(v);
        autoLayout.lockVertex(v);
    }
    this.addVertex(vertex);
    vv.getModel().restart();
    autoVv.getModel().restart();
    
    for(Iterator<?> iterator=this.getVertices().iterator(); iterator.hasNext(); ) {
	Vertex v= (Vertex)iterator.next();layout.unlockVertex(v);
        autoLayout.unlockVertex(v);
    }
    
    if(!task.equals(startTask))
      this.addEdge(getStartTask(),task);
    
    if(!task.equals(startTask) && !task.equals(endTask))
      this.addEdge(task,getEndTask());
    
 
  }
  
  public void addVertex (Task task, Point2D point){
    /* Creation of Vertex*/ 
    Vertex vertex = new OurVertex();
    vertex.addUserDatum("Key",task,UserData.REMOVE);
    mapNomVertex.put(task,vertex);
    
    task.setLocation(point);
    task.setAutoLocation(point);
    
    vertexLocations.setLocation(vertex, vv.inverseTransform(point));
    autoVertexLocations.setLocation(vertex, vv.inverseTransform(point));
    

    for(Iterator<?> iterator=this.getVertices().iterator(); iterator.hasNext(); ) {
	Vertex v= (Vertex)iterator.next();
        autoLayout.unlockVertex(v);
        layout.lockVertex(v);
    }
    this.addVertex(vertex);
    
    vv.getModel().restart();
    autoVv.getModel().restart();	
    
    for(Iterator<?> iterator=this.getVertices().iterator(); iterator.hasNext(); ) {
	Vertex v= (Vertex)iterator.next();
        autoLayout.unlockVertex(v);
        layout.lockVertex(v);
    }
    
    if(!task.equals(startTask))
      this.addEdge(getStartTask(),task);
    
    if(!task.equals(startTask) && !task.equals(endTask))
      this.addEdge(task,getEndTask());
    
//    Task taskTemp = this.parse();
//    Graph graph = taskTemp.getGraph();
//    if(graph != null){
//      try {
//        graph.criticalPath(true,Direction.BOTH);
//      } catch (CyclicGraphException ex) {}
//    }
    
    if(this.numVertices() == 3){
      this.startTask.getSuperTask().setDetailled(true);
//    if(this.getStartTask().getSuperTask() != null)
//      this.getStartTask().updateMotherDuration();
      this.workSpace.getCurrentProject().getGraph().criticalPath(true);
    }
    
    
  }  
  
  
  
  
  public void setLocation(Task t, Point2D p){
    vertexLocations.setLocation(getVertex(t), p);
    vv.getModel().restart();
  }
  
  public void setAutoLocation(Task t, Point2D p){
    autoVertexLocations.setLocation(getVertex(t), p);
    autoVv.getModel().restart();
  }
    
  
  public void addEdge(Task t1, Task t2){
    
    DirectedSparseEdge e = new DirectedSparseEdge(getVertex(t1), getVertex(t2));
    try{
    this.addEdge(e);
    //System.out.println("new Edge : " + t1.getName() +", " + t2.getName());
    
    
    boolean isCyclic = false;
    try {
      this.topoSort(false);
    } catch (CyclicGraphException ex) {
      removeEdge(e);
      isCyclic = true;
    }
    if(!isCyclic)
    {
      Edge edgeTemp = getVertex(getStartTask()).findEdge(getVertex(t2));
      if(!t1.equals(startTask))
      {
        if(edgeTemp != null)
          super.removeEdge(edgeTemp);
      }
      if(!t2.equals(endTask))
      {
        edgeTemp = getVertex(t1).findEdge(getVertex(getEndTask()));
        if(edgeTemp != null)
          super.removeEdge(edgeTemp);
      }
//      Task taskTemp = this.parse();
//      taskTemp.updateActualBeginTime();
//      Graph graph = taskTemp.getGraph();
//      if(graph != null){
//        try {
//          graph.criticalPath(true,Direction.BOTH);
//        } catch (CyclicGraphException ex) {}
//      }
      if(startTask.getSuperTask() != null)
        if(startTask.getSuperTask().isDetailled())
          this.workSpace.getCurrentProject().getGraph().criticalPath(true);
      
      //t2.setActualBeginTime(t1.getActualEndTime(), true);
//      if(this.getStartTask().getSuperTask() != null)
//        this.getStartTask().updateMotherDuration();
    }
    }
    catch (ConstraintViolationException ex) {}
      
    
  }
  
  //////////////////////////////////////////////////////////////////////////////

  private void initVertex(OurVertex vertex){
    
    if(!getTask(vertex).equals(this.getEndTask()))
      for(Object o : vertex.getPredecessors())
      {
        OurVertex pred = (OurVertex)o;
        if(pred.numSuccessors() == 1)
          this.addEdge(this.getTask(pred), this.getEndTask());
      }
    
    if(!getTask(vertex).equals(this.getStartTask()))
      for(Object o : vertex.getSuccessors())
      {
        OurVertex succ = (OurVertex)o;
        if(succ.numPredecessors() == 1)
          this.addEdge(this.getStartTask(), this.getTask(succ));
      }
  }
  
  
  /**
  * Removes a task from the graph
  *
  * @param task the task to be removed
  * 
  */
  public void removeVertex(Task task){
    OurVertex v = this.getVertex(task);
    Set neighbors = v.getNeighbors();
    removeVertex(v);
    for(Object o : neighbors)
    {
      if(!((OurVertex)o).equals(v))
        update((OurVertex)o);
    }
    if(this.numVertices() == 2){
      this.startTask.getSuperTask().setDetailled(false);
      this.startTask.getSuperTask().setDuration(1, true);
    }
    
    this.workSpace.getCurrentProject().getGraph().criticalPath(true);
    
  }
  
  /**
  * Removes an edge from the graph
  *
  * @param e the edge to be removed
  * 
  */
  public void removeEdge(DirectedSparseEdge e){
    
    Set vertices = e.getIncidentVertices();
    super.removeEdge((Edge)e);
    
    for(Object o : vertices)
      update((OurVertex)o);
     
    this.workSpace.getCurrentProject().getGraph().criticalPath(true);
    
  }
  
  public Task parse()
  {
    Task taskTemp = this.getStartTask();
    while(taskTemp.getSuperTask() != null){
      System.out.println("parsing");
      taskTemp = taskTemp.getSuperTask();
    }
    return taskTemp;
  }
  
  
  private void update(OurVertex v){
    
    if(v.numPredecessors() == 0 && !getTask(v).equals(startTask))
      addEdge(startTask, getTask(v));
    if(v.numSuccessors() == 0 && !getTask(v).equals(endTask))
      addEdge(getTask(v), endTask);
  }
  
  
  //////////////////////////////////////////////////////////////////////////////

  /**
  * Replaces a vertex by another one
  *
  * @param oldVertex the vertex to be replaced
  * @param newVertex the replacement vertex
  * 
  */

  public void changeVertex(Task oldTask, Task newTask){
    this.removeVertex(oldTask);
    this.addVertex(newTask);
  }

  
  public Task getTask(OurVertex v)
  {
    return (Task)this.mapNomVertex.getKey(v);
  }  
  public Task getStartTask(){
    return startTask;
  }

  public void setStartTask(Task startTask){
    this.startTask = startTask;
	this.addVertex(startTask);
  }

  public Task getEndTask(){
    return endTask;
  }

  public void setEndTask(Task endTask){
    this.endTask = endTask;
  }

  public LinkedList<Task> getSortedTasks(){
    return sortedTasks;
  }
  //////////////////////////////////////////////////////////////////////////////

  public DualHashBidiMap getMapNomVertex(){
    return this.mapNomVertex;
  }

  //////////////////////////////////////////////////////////////////////////////
  
  /**
  * sets all the vertices to "not met"
  * 
  */
  public void initVerticesVisits()
  {
    for(Object o : this.getVertices())
      ((OurVertex)o).setVisited(false);
  }
  
  
  public void criticalPath(boolean isExtended){
//    Task taskTemp = this.workSpace.getCurrentProject().getGraph().parse();
//    Graph graph = taskTemp.getGraph();    
    try {
      this.workSpace.getCurrentProject().getGraph().criticalPath(isExtended, Direction.BOTH);
    } catch (CyclicGraphException ex) {}
  }
  
  
  /**
  * does the topologic sort
  * 
  * @param extended sets whether the sort is executed for the sub-tasks
  */  
  public LinkedList<Task> topoSort(Boolean extended) throws CyclicGraphException
  {
    //System.out.println("topo sort");
    LinkedList<OurVertex> vertecesInDegreeZero = new LinkedList<OurVertex>();
    this.sortedTasks.clear();
	
    this.initVerticesVisits();
    for(Object o : this.getVertices())
    {
      OurVertex v = (OurVertex)o;
      v.setInDegree(v.numPredecessors());
      if(v.getInDegree() == 0)
      {
        //System.out.println("topo : degre 0 : "+v.getName());
        vertecesInDegreeZero.add(v);
      }
    }
    while(!vertecesInDegreeZero.isEmpty())
    {
      OurVertex v = vertecesInDegreeZero.removeFirst();
      this.sortedTasks.add(this.getTask(v));
      v.setVisited(true);
      if(extended && this.getTask(v).isDetailled())
        sortedTasks.addAll(this.getTask(v).getGraph().topoSort(extended));
      for(Object o : v.getSuccessors())
      {
        OurVertex s = (OurVertex)o;
        s.setInDegree(s.getInDegree() - 1);
        
        if(s.getInDegree() == 0)
          vertecesInDegreeZero.add(s);
      }
    }
    for(Object o : getVertices())
      if(!((OurVertex)o).isVisited())
        throw new CyclicGraphException();
    
    return sortedTasks;
  }
  
  
  /**
  * Computes the earliest and the latest begin time of each task and determines
  * the critical path.
  * 
  * @param extended sets whether the sort is executed for the sub-tasks
  */  
  protected void criticalPath(boolean isExtended, Direction d) throws CyclicGraphException{
    //System.out.println("Critical path");
    
    if(this.startTask.getSuperTask() != null)
    {
      
      LinkedList<Task> tasks;
      if(d != Direction.BACKWARD)
      {
        Calendar calTmp = Calendar.getInstance();
        tasks = this.topoSort(false);
        Task start = tasks.removeFirst();
        start.setEarliestBeginTime(start.getSuperTask().getEarliestBeginTime(),true);
        start.setActualBeginTime(start.getEarliestBeginTime(), true);
        start.setLatestBeginTime(start.getEarliestBeginTime(),true);
        
        for(Task j : tasks)
        {
          //System.out.println("Current task : " + j.getName());
          j.setEarliestBeginTime(start.getEarliestBeginTime(), true);
          //j.setActualBeginTime(start.getActualBeginTime(), true);

          for(Object o : this.getVertex(j).getPredecessors())
          {
            Task i = this.getTask((OurVertex)o);
            
            calTmp.setTime(i.getEarliestBeginTime().getTime());
            calTmp.add(Calendar.DATE, i.getDuration());
            if(j.getEarliestBeginTime().get(Calendar.YEAR) <= calTmp.get(Calendar.YEAR))
              if(j.getEarliestBeginTime().get(Calendar.DAY_OF_YEAR) < calTmp.get(Calendar.DAY_OF_YEAR)){
                j.setEarliestBeginTime(calTmp, true);         
              }
            // mise a jour de 
            j.setLatestBeginTime(calTmp, true);
            j.setActualBeginTime(calTmp, true);
          }
          
          if(j.isDetailled() && isExtended)
          //if(j.getGraph() != null)
            j.getGraph().criticalPath(isExtended, Direction.FORWARD);
        }
      }

      if(d != Direction.FORWARD)
      {
        tasks = topoSort(false);
        Task end = tasks.removeLast();
        
        end.getSuperTask().setDuration((int)((end.getEarliestBeginTime().getTimeInMillis() - 
                  end.getSuperTask().getGraph().getStartTask().getEarliestBeginTime().getTimeInMillis())/(1000*3600*24)), false);
        
        Calendar cal = Calendar.getInstance();
        int decal = (int)((end.getSuperTask().getLatestBeginTime().getTimeInMillis() - 
                end.getSuperTask().getEarliestBeginTime().getTimeInMillis())/(1000*3600*24));

        cal.setTime(end.getEarliestBeginTime().getTime());
        cal.add(Calendar.DATE, decal);
        end.setLatestBeginTime(cal, true);
        //if(end.getSuperTask().equals(workSpace.getCurrentProject()))
          
        cal.setTime(end.getActualBeginTime().getTime());
        cal.add(Calendar.DATE, -1);
        end.setActualEndTime(cal, false);
        //end.getSuperTask().setActualBeginTime(cal, true);
        //cal.add(Calendar.DATE, -1);
        //end.getSuperTask().setActualEndTime(cal,true);
                
        //if(end.getSuperTask().isDetailled()){
          end.getSuperTask().setEarliestEndTime(end.getEarliestEndTime());
//          cal.setTime(end.getLatestBeginTime().getTime());
//          cal.add(Calendar.DATE, -1);
          //end.getSuperTask().setDuration((int)((end.getEarliestBeginTime().getTimeInMillis() - 
                 // end.getSuperTask().getGraph().getStartTask().getEarliestBeginTime().getTimeInMillis())/(1000*3600*24)), false);
        //System.out.println("LASDKJLKFALDKSJFLKJDLKSJFLKJSDLKFJSLDKAJ       " + end.getSuperTask().getDuration());
       // }
        //end.getSuperTask().setActualEndTime(cal, end.getSuperTask().isDetailled());
          
        //end.setCritical(true);

        Iterator<Task> iter = tasks.descendingIterator();

        while(iter.hasNext())
        {
          Task j = iter.next();
          j.setLatestBeginTime(end.getEarliestBeginTime(), true);

          for(Object o : getVertex(j).getSuccessors())
          {
            Task k = getTask((OurVertex)o);
            //Calendar calTmp = Calendar.getInstance();
            cal.setTimeInMillis(k.getLatestBeginTime().getTimeInMillis());
            cal.add(Calendar.DATE, -j.getDuration());

            if(j.getLatestBeginTime().get(Calendar.YEAR) >= cal.get(Calendar.YEAR))
              if(j.getLatestBeginTime().get(Calendar.DAY_OF_YEAR) > cal.get(Calendar.DAY_OF_YEAR)){
                j.setLatestBeginTime(cal, true);

            }
            j.setLatestBeginTime(cal, true);
            cal.add(Calendar.DATE, j.getDuration()-1);
            j.setLatestEndTime(cal);
                    

            if(j.getEarliestBeginTime().get(Calendar.DAY_OF_YEAR) == j.getLatestBeginTime().get(Calendar.DAY_OF_YEAR) && 
                    j.getEarliestBeginTime().get(Calendar.YEAR) == j.getLatestBeginTime().get(Calendar.YEAR)){
              j.setCritical(true); 
            }
            else
              j.setCritical(false);

            if(j.isDetailled() && isExtended)
              j.getGraph().criticalPath(isExtended, Direction.BACKWARD);
          }
        }
      }
    }
  }
  
  public LinkedList<LinkedList<OurVertex>> deepSort()
  {
    LinkedList<LinkedList<OurVertex>> columnList = new LinkedList<LinkedList<OurVertex>>();
    LinkedList<OurVertex> lineList = new LinkedList<OurVertex>();
    
    OurVertex start = this.getVertex(startTask);
    lineList.add(start);
    
    
    LinkedList<OurVertex>tmp = new LinkedList<OurVertex>();
    int i = 1;
    int j = 1;
    while(true)
    {
      columnList.add(lineList);
      for(Object v : lineList)
      {
        //System.out.println("DS v : " + ((OurVertex)v).getTask().getName());
        for(Object s : ((OurVertex)v).getSuccessors()){
          if(!tmp.contains(s))
            tmp.add((OurVertex)s);
          //System.out.println("DS s : " + ((OurVertex)s).getTask().getName());
        }
        
      }
      if (tmp.isEmpty())
        break;
      lineList = tmp;
      
      
      
      tmp = new LinkedList<OurVertex>();
//      for(OurVertex v : lineList)
//        System.out.println("LineList "+i+": " + v.getTask().getName());
    }
    
    return columnList;
  }
  
  
  public DefaultSettableVertexLocationFunction getVertexLocations() {
    return vertexLocations;
  }

  public void setVertexLocations(DefaultSettableVertexLocationFunction vertexLocations) {
    this.vertexLocations = vertexLocations;
  }

  public VisualizationViewer getVv() {
    return vv;
  }

  public void setVv(VisualizationViewer vv) {
    this.vv = vv;
  }

  public AbstractLayout getLayout() {
    return layout;
  }

  public void setLayout(AbstractLayout layout) {
    this.layout = layout;
  }
  
  
  public DefaultSettableVertexLocationFunction getAutoVertexLocations() {
    return autoVertexLocations;
  }

  public void setAutoVertexLocations(DefaultSettableVertexLocationFunction autoVertexLocations) {
    this.autoVertexLocations = autoVertexLocations;
  }

  public VisualizationViewer getAutoVv() {
    return autoVv;
  }

  public void setAutoVv(VisualizationViewer autoVv) {
    this.autoVv = autoVv;
  }

  public AbstractLayout getAutoLayout() {
    return autoLayout;
  }

  public void setAutoLayout(AbstractLayout autoLayout) {
    this.autoLayout = autoLayout;
  }
  
  
  
  public void writeJPEGImage(String filename, boolean title, JPanel printPanel) {
    int width = printPanel.getSize().width;
    int height = printPanel.getSize().height;

    BufferedImage bi = new BufferedImage(width,height,BufferedImage.TYPE_INT_BGR);
    Graphics2D graphics = bi.createGraphics();
    graphics.setColor(Color.WHITE);
    graphics.fillRect(0,0, width, height);
    printPanel.paint(graphics);
   
    try{
       ImageIO.write(bi,"png",new File(filename));
    }catch(Exception e){e.printStackTrace();}
    
    if (title){
      graphics.setFont(new java.awt.Font("Comic Sans MS", 3, 80));
      graphics.drawString(workSpace.getCurrentProject().getName(), 200, 300);
      try{
        ImageIO.write(bi,"png",new File(filename.substring(0, filename.lastIndexOf("."))+"title.jpg"));
      }catch(Exception e){e.printStackTrace();}
    }

} 
    
    
    
    
  public static void main(String[] args)
  {
    Workspace ws = new Workspace();
    Project project1 = new Project("Project1", ws);
    Calendar start = Calendar.getInstance();
    start.set(Calendar.DATE, 10);
    project1.setEarliestBeginTime(start,true);
    project1.addGraph(null);
//
    //Task s = new Task("s",10);
    Task a = new Task("a",1,ws);
    Task b = new Task("b",4,ws);
    Task c = new Task("c",2,ws);
////    Task d = new Task("d",30);
////    Task e = new Task("e",20);
////    
////    e.addGraph();
////    
////    Task q = new Task("q",5);
////    Task r = new Task("r",10);
////    Task t = new Task("t",5);
////    
////    e.getGraph().addVertex(q);
////    e.getGraph().addVertex(r);
////    e.getGraph().addVertex(t);
////    e.getGraph().addEdge(q, r);
////    e.getGraph().addEdge(q, t);
////    e.getGraph().addEdge(r, t);
////    
////    project1.getGraph().addVertex(s);
    project1.getGraph().addVertex(a);
    project1.getGraph().addVertex(b);
    project1.getGraph().addVertex(c);
////    project1.getGraph().addVertex(d);
////    project1.getGraph().addVertex(e);

    project1.getGraph().addEdge(a,b);
    project1.getGraph().addEdge(a,c);
////    project1.getGraph().addEdge(s,c);
////    project1.getGraph().addEdge(s,d);
////    project1.getGraph().addEdge(s,a);
////    project1.getGraph().addEdge(c,a);
////    project1.getGraph().addEdge(d,e);
////    project1.getGraph().addEdge(s,e);
////    project1.getGraph().addEdge(e,b);
////    project1.getGraph().addEdge(b,a);
//    
//    
//    
//    //Task project2 = new Task("Project2");
//    
//    project2.addGraph();
//    //Task a = new Task("a",5);
//    //Task b = new Task("b",10);
//    //Task c = new Task("c",10);
//    //Task d = new Task("d",20);
//    //Task e = new Task("e",15);
//    //Task f = new Task("f",30);
//    //Task g = new Task("g",15);
//    //Task h = new Task("h",10);
//    
//    project2.getGraph().addVertex(a);
//    project2.getGraph().addVertex(b);
//    project2.getGraph().addVertex(c);
//    project2.getGraph().addVertex(d);
//    project2.getGraph().addVertex(e);
//    project2.getGraph().addVertex(f);
//    project2.getGraph().addVertex(g);
//    project2.getGraph().addVertex(h);
//    
//    project2.getGraph().addEdge(a, c);
//    project2.getGraph().addEdge(a, d);
//    project2.getGraph().addEdge(b, e);
//    project2.getGraph().addEdge(c, f);
//    project2.getGraph().addEdge(d, g);
//    project2.getGraph().addEdge(e, g);
//    project2.getGraph().addEdge(f, h);
//    project2.getGraph().addEdge(g, h);
//    
//    f.addGraph();
//    //Task f1 = new Task("f1",20);
//    //Task f2 = new Task("f2",5);
//    //Task f3 = new Task("f3",5);
//    //Task f4 = new Task("f5",10);
//    
//    f.getGraph().addVertex(f1);
//    f.getGraph().addVertex(f2);
//    f.getGraph().addVertex(f3);
//    f.getGraph().addVertex(f4);
//    
//    f.getGraph().addEdge(f1, f4);
//    f.getGraph().addEdge(f2, f3);
//    f.getGraph().addEdge(f3, f4);
//    
//    //Task cycle = new Task("");
//    cycle.addGraph();
//    //Task c1 = new Task("c1");
//    //Task c2 = new Task("c2");
//    //Task c3 = new Task("c3");
//    cycle.getGraph().addVertex(c1);
//    cycle.getGraph().addVertex(c2);
//    cycle.getGraph().addVertex(c3);
//    cycle.getGraph().addEdge(c1, c2);
//    cycle.getGraph().addEdge(c2, c3);
//    cycle.getGraph().addEdge(c3, c1);
//
//    boolean extended = true;
//    
    try {
      project1.getGraph().criticalPath(false, Direction.BOTH);
    } 
    catch (CyclicGraphException ex) {
      System.out.println("The Graph is cyclic");
    }
    
    for(Object o : project1.getGraph().getVertices())
    {
      System.out.println(((OurVertex)o).getTask());
    }
//    try {
//      for (Task task : cycle.getGraph().topoSort(extended)){
//        System.out.println(task);
//      }
//    } catch (CyclicGraphException ex) {
//      System.out.println("The Graph is cyclic");
//    }
//    
//    
  }
}

  //////////////////////////////////////////////////////////////////////////////
